package com.xuyuan.util;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import com.jayway.jsonpath.Option;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JsonPathUtil {
    private static final Logger LOGGER = LoggerFactory.getLogger(JsonPathUtil.class);
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
    static Configuration config;

    static {
        // config = Configuration.builder().jsonProvider(new JacksonJsonNodeJsonProvider()).mappingProvider(new JacksonMappingProvider()).options(Option.AS_PATH_LIST).build();
        config = com.jayway.jsonpath.Configuration.defaultConfiguration().addOptions(Option.AS_PATH_LIST);
    }

    public static <T> T replaceAllKey(T target, String key, Object value) {
        try {
            String jsonString = target instanceof String ? (String) target : OBJECT_MAPPER.writeValueAsString(target);
            DocumentContext context = JsonPath.using(config).parse(jsonString);
            context.set("$.." + key, value);
            if (target instanceof String) return (T) context.jsonString();
            else return OBJECT_MAPPER.readValue(context.jsonString(), (Class<T>) target.getClass());
        } catch (Exception e) {
            LOGGER.error("JsonPath replace error", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T replaceAllKey(T target, Pair<String, Object> keyValuePair) {
        try {
            String jsonString = target instanceof String ? (String) target : OBJECT_MAPPER.writeValueAsString(target);
            DocumentContext context = JsonPath.using(config).parse(jsonString);
            context.set("$.." + keyValuePair.getKey(), keyValuePair.getValue());
            if (target instanceof String) return (T) context.jsonString();
            else return OBJECT_MAPPER.readValue(context.jsonString(), (Class<T>) target.getClass());
        } catch (Exception e) {
            LOGGER.error("JsonPath replace error", e);
            throw new RuntimeException(e);
        }
    }


    public static <T> T replaceAllKeyWithGeneric(T target, String key, Object value, TypeReference<T> toValueTypeRef) {
        try {
            DocumentContext context = JsonPath.using(config).parse(OBJECT_MAPPER.writeValueAsString(target));
            context.set("$.." + key, value);
            return OBJECT_MAPPER.readValue(context.jsonString(), toValueTypeRef);
        } catch (Exception e) {
            LOGGER.error("JsonPath replace error", e);
            throw new RuntimeException(e);
        }
    }

    public static <T> T replaceAllKeyWithGeneric(T target, Pair<String, Object> keyValuePair, TypeReference<T> toValueTypeRef) {
        try {
            DocumentContext context = JsonPath.using(config).parse(OBJECT_MAPPER.writeValueAsString(target));
            context.set("$.." + keyValuePair.getKey(), keyValuePair.getValue());
            return OBJECT_MAPPER.readValue(context.jsonString(), toValueTypeRef);
        } catch (Exception e) {
            LOGGER.error("JsonPath replace error", e);
            throw new RuntimeException(e);
        }
    }

    public static void validateJson(String json) {
        if (json == null || json.trim().isEmpty()) {
            LOGGER.error("JSON cannot be null or empty");
            throw new IllegalArgumentException("JSON cannot be null or empty");
        }
        try {
            OBJECT_MAPPER.readTree(json);
        } catch (Exception e) {
            LOGGER.error("Invalid JSON format", e);
            throw new IllegalArgumentException("Invalid JSON format", e);
        }
    }

}
